/*
 *
 * Copyright 2018 galaxyobe.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use s file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package grpc

import (
	"net"

	"google.golang.org/grpc"
	"google.golang.org/grpc/reflection"
)

// Server interface
type Server interface {
	// Register grpc implement
	Register(func(*grpc.Server))
	// Start the grpc service
	ListenAndServe(string) error
	// Serve accepts incoming connections on the listener lis, creating a new
	// ServerTransport and service goroutine for each. The service goroutines
	// read gRPC requests and then call the registered handlers to reply to them.
	// Serve returns when lis.Accept fails with fatal errors.  lis will be closed when
	// this method returns.
	// Serve will return a non-nil error unless Stop or GracefulStop is called.
	Serve(net.Listener) error
	// Stop stops the gRPC server. It immediately closes all open
	// connections and listeners.
	// It cancels all active RPCs on the server side and the corresponding
	// pending RPCs on the client side will get notified by connection
	// errors.
	Stop()
	// GracefulStop stops the gRPC server gracefully. It stops the server from
	// accepting new connections and RPCs and blocks until all the pending RPCs are
	// finished.
	GracefulStop()
}

// Server interface implement
type server struct {
	*grpc.Server
}

// NewServer is create a new grpc server
//
// @param opt ...grpc.ServerOption - the grpc option
//
// @return Server - the Server interface
//
func NewServer(opt ...grpc.ServerOption) Server {

	server := &server{}
	server.Server = grpc.NewServer(opt...)

	return server
}

// Register grpc implement
//
// @param f func(*grpc.Server) - the grpc server implement register function
//
func (s *server) Register(f func(*grpc.Server)) {
	if f != nil {
		f(s.Server)
	}
}

// Start the grpc service
//
// @param addr string - the grpc server ip address and port
//
// @return error - listen failed or grpc serve failed error
//
func (s *server) ListenAndServe(addr string) error {
	lis, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	// Register reflection service on gRPC server.
	reflection.Register(s.Server)
	return s.Server.Serve(lis)
}
